<template>
  <el-sub-menu :index="props.index">
    <template #title>交互事件</template>
    <el-menu-item index="7-1" @click="handlerEllipsoid">鼠标点击坐标</el-menu-item>
    <el-menu-item index="7-2" @click="pointHandler">标点</el-menu-item>
    <el-menu-item index="7-3" @click="polylineHandler">画线段</el-menu-item>
    <el-menu-item index="7-4" @click="pickObj">点击拾取模型</el-menu-item>
  </el-sub-menu>
</template>

<script setup>
import * as Cesium from 'cesium'
import { useCesiumStore } from '@/stores/cesiumStore'
import { ref, onMounted, onUnmounted } from 'vue'

// 定义props
const props = defineProps({
  index: {
    type: String,
    required: true,
  },
})

// 使用 Cesium Store
const cesiumStore = useCesiumStore()
//获取位置
const handlerEllipsoid = () => {
  //深度检测开起,默认是关闭的
  cesiumStore.viewerCesium.scene.globe.depthTestAgainstTerrain = true
  // setInputAction进行监听，可监听点击、移入移除移动事件等
  const handler = new Cesium.ScreenSpaceEventHandler(cesiumStore.viewerCesium.scene.canvas)
  handler.setInputAction(function (click) {
    const ray = cesiumStore.viewerCesium.camera.getPickRay(click.position)
    const position = cesiumStore.viewerCesium.scene.globe.pick(ray, cesiumStore.viewerCesium.scene)
    if (position) {
      console.log('点击地方的笛卡尔3坐标：', position)
      const cartesian3Value = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position) //转弧度
      console.log('点击地方的W84弧度坐标：', cartesian3Value)
      const longitude = Cesium.Math.toDegrees(cartesian3Value.longitude)
      const latitude = Cesium.Math.toDegrees(cartesian3Value.latitude)
      const height = cartesian3Value.height
      console.log('点击地方的W84经纬度坐标：', longitude, ',', latitude, ',', height)
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK) //鼠标左击
  // 添加右键点击事件，用于停止添加点
  handler.setInputAction(function (movement) {
    // 销毁事件句柄，停止添加点
    handler.destroy()
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
//标点
const pointHandler = () => {
  const handler = new Cesium.ScreenSpaceEventHandler(cesiumStore.viewerCesium.scene.canvas)

  handler.setInputAction(function (click) {
    // 从屏幕坐标获取射线
    const ray = cesiumStore.viewerCesium.camera.getPickRay(click.position)
    // 计算射线与地球表面的交点位置
    const position = cesiumStore.viewerCesium.scene.globe.pick(ray, cesiumStore.viewerCesium.scene)

    if (position) {
      // 在点击位置添加实体（红色点）
      const entity = cesiumStore.viewerCesium.entities.add({
        position: position,
        point: {
          // 圆点
          pixelSize: 15,
          color: Cesium.Color.RED,
          outlineColor: Cesium.Color.WHITE,
          outlineWidth: 2,
        },
      })
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  // 添加右键点击事件，用于停止添加点
  handler.setInputAction(function (movement) {
    // 销毁事件句柄，停止添加点
    handler.destroy()
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}

/**
 * 绘制折线并显示距离的处理函数
 * 功能：
 * 1. 左键点击添加点
 * 2. 显示每段线段的距离
 * 3. 右键结束绘制并显示总距离
 * 4. 鼠标移动时预览下一段线段
 */
const polylineHandler = () => {
  // 创建Cesium屏幕空间事件处理器，用于捕获鼠标事件
  const handler = new Cesium.ScreenSpaceEventHandler(cesiumStore.viewerCesium.scene.canvas)

  // 状态变量
  let accumulatedDistance = 0 // 累计总距离(米)
  let polylineEntity = null // 存储线段实体引用
  const positions = ref([])
  const pointEntities = [] // 存储点实体引用数组
  const segmentLabelEntities = [] // 存储线段距离标签实体引用数组

  // 样式配置常量
  const STYLES = {
    // 点的样式
    POINT: {
      pixelSize: 5, // 点大小
      color: Cesium.Color.RED, // 点颜色
      outlineColor: Cesium.Color.WHITE, // 点外边框颜色
      outlineWidth: 2, // 点外边框宽度
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 贴地显示
    },
    // 点标签样式
    POINT_LABEL: {
      font: '14px sans-serif', // 字体
      fillColor: Cesium.Color.WHITE, // 填充颜色
      style: Cesium.LabelStyle.FILL_AND_OUTLINE, // 标签样式：填充+轮廓
      outlineWidth: 2, // 轮廓宽度
      outlineColor: Cesium.Color.BLACK, // 轮廓颜色
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 垂直对齐方式：底部对齐
      pixelOffset: new Cesium.Cartesian2(0, -10), // 像素偏移量
      showBackground: true, // 显示背景
      backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.7), // 背景颜色
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 贴地显示
    },
    // 线段距离标签样式
    SEGMENT_LABEL: {
      font: '14px sans-serif', // 字体
      fillColor: Cesium.Color.YELLOW, // 填充颜色：黄色更醒目
      style: Cesium.LabelStyle.FILL_AND_OUTLINE, // 标签样式：填充+轮廓
      outlineWidth: 2, // 轮廓宽度
      outlineColor: Cesium.Color.BLACK, // 轮廓颜色
      verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直对齐方式：居中
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平对齐方式：居中
      showBackground: true, // 显示背景
      backgroundColor: new Cesium.Color(0.1, 0.1, 0.1, 0.7), // 背景颜色：深色背景
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 贴地显示
      disableDepthTestDistance: Number.POSITIVE_INFINITY, // 禁用深度测试，确保标签始终可见
    },
    // 总距离标签样式
    TOTAL_LABEL: {
      font: 'bold 16px sans-serif', // 字体：加粗且更大
      fillColor: Cesium.Color.WHITE, // 填充颜色
      style: Cesium.LabelStyle.FILL_AND_OUTLINE, // 标签样式：填充+轮廓
      outlineWidth: 2, // 轮廓宽度
      outlineColor: Cesium.Color.BLACK, // 轮廓颜色
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 垂直对齐方式：底部对齐
      pixelOffset: new Cesium.Cartesian2(0, -30), // 像素偏移量
      showBackground: true, // 显示背景
      backgroundColor: new Cesium.Color(0.1, 0.3, 0.6, 0.8), // 背景颜色：蓝色调
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 贴地显示
    },
    // 折线样式
    POLYLINE: {
      material: Cesium.Color.CHARTREUSE, // 线条颜色：亮绿色
      width: 2, // 线宽
      clampToGround: true, // 贴地显示
    },
  }

  /**
   * 获取鼠标点击位置对应的地表坐标
   */
  const getGroundPosition = (clickPosition) => {
    // 从相机位置创建一条射线
    const ray = cesiumStore.viewerCesium.camera.getPickRay(clickPosition)
    // 计算射线与地球表面的交点           //获取射线与地球表面的交点
    return cesiumStore.viewerCesium.scene.globe.pick(ray, cesiumStore.viewerCesium.scene)
  }

  /**
   * 创建点实体
   * @param {Cesium.Cartesian3} position - 点的位置
   * @param {number} index - 点的索引
   * @returns {Cesium.Entity} - 创建的点实体
   */
  const createPoint = (position, index) => {
    // 第一个点显示起点，其他点显示序号
    const labelText = index === 0 ? '起点' : `点${index}`

    // 创建并返回点实体
    return cesiumStore.viewerCesium.entities.add({
      position: position,
      point: { ...STYLES.POINT }, // 应用点样式
      label: {
        ...STYLES.POINT_LABEL, // 应用标签样式
        text: labelText, // 设置标签文本
      },
    })
  }

  /**
   * 计算两点之间的中点位置
   * @param {Cesium.Cartesian3} point1 - 第一个点
   * @param {Cesium.Cartesian3} point2 - 第二个点
   * @returns {Cesium.Cartesian3} - 中点坐标
   */
  const calculateMidpoint = (point1, point2) => {
    ////Cesium.Cartesian3.midpoint()函数会返回作为第三个参数传入的那个对象 返回的就是这个被修改后的对象
    return Cesium.Cartesian3.midpoint(point1, point2, new Cesium.Cartesian3())
  }

  /**
   * 计算两点之间的距离（米）
   * @param {Cesium.Cartesian3} point1 - 第一个点
   * @param {Cesium.Cartesian3} point2 - 第二个点
   * @returns {number} - 距离（米）
   */
  const calculateSegmentDistance = (point1, point2) => {
    // 使用Cesium的距离计算函数计算两点间的笛卡尔距离
    return Cesium.Cartesian3.distance(point1, point2) //计算两点之间的距离。
  }

  /**
   * 创建线段距离标签
   * @param {Cesium.Cartesian3} startPosition - 线段起点
   * @param {Cesium.Cartesian3} endPosition - 线段终点
   * @param {number} distance - 距离值（米）
   * @returns {Cesium.Entity} - 创建的标签实体
   */
  const createSegmentLabel = (startPosition, endPosition, distance) => {
    // 计算线段中点作为标签位置
    const midpoint = calculateMidpoint(startPosition, endPosition)

    // 创建标签实体
    const labelEntity = cesiumStore.viewerCesium.entities.add({
      position: midpoint,
      label: {
        ...STYLES.SEGMENT_LABEL, // 应用线段标签样式
        text: `${distance.toFixed(2)} 米`, // 格式化距离文本，保留2位小数
      },
    })

    return labelEntity
  }

  /**
   * 更新或创建折线实体
   */
  const updatePolyline = () => {
    // 如果已有线段实体，则更新它，否则创建新的
    if (polylineEntity) {
      polylineEntity.polyline.positions = positions.value
    } else {
      polylineEntity = cesiumStore.viewerCesium.entities.add({
        polyline: {
          show: true,
          positions: positions.value,
          ...STYLES.POLYLINE, // 应用折线样式
        },
      })
    }
  }

  // 注册左键点击事件处理函数
  handler.setInputAction((click) => {
    // 获取点击位置对应的地表坐标
    const position = getGroundPosition(click.position)

    if (!position) return // 如果没有获取到有效位置，直接返回

    // 将点击位置添加到线段顶点数组
    positions.value.push(position)
    const currentIndex = positions.value.length - 1 //最后一个点的索引

    // 添加点标记并存储引用
    const pointEntity = createPoint(position, currentIndex)
    pointEntities.push(pointEntity)

    // 如果有两个或更多点，则计算并显示线段距离
    if (positions.value.length > 1) {
      const prevPosition = positions.value[currentIndex - 1]
      const currentPosition = positions.value[currentIndex]

      // 计算当前段距离
      const segmentDistance = parseFloat(calculateSegmentDistance(prevPosition, currentPosition))

      // 累加到总距离
      accumulatedDistance += segmentDistance

      // 在线段中间添加距离标签
      const segmentLabel = createSegmentLabel(prevPosition, currentPosition, segmentDistance)
      segmentLabelEntities.push(segmentLabel)
    }

    // 更新或创建线段
    updatePolyline()
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  // 注册鼠标移动事件处理函数，用于显示临时线段（预览效果）
  handler.setInputAction((movement) => {
    // 只有当至少有一个点时才显示临时线段
    if (positions.value.length >= 1) {
      // 获取鼠标当前位置对应的地表坐标
      const tempPosition = getGroundPosition(movement.endPosition)

      if (tempPosition) {
        // 创建临时位置数组，包含所有现有点加上当前鼠标位置
        const tempPositions = [...positions.value, tempPosition]

        // 更新或创建临时线段
        if (polylineEntity) {
          polylineEntity.polyline.positions = tempPositions
        } else {
          polylineEntity = cesiumStore.viewerCesium.entities.add({
            polyline: {
              show: true,
              positions: tempPositions,
              ...STYLES.POLYLINE,
              material: Cesium.Color.fromAlpha(STYLES.POLYLINE.material, 0.7), // 半透明效果
            },
          })
        }

        // 如果已经有至少一个点，可以计算临时距离
        if (positions.value.length >= 1) {
          const lastPosition = positions.value[positions.value.length - 1]
          const tempDistance = parseFloat(calculateSegmentDistance(lastPosition, tempPosition))

          // 这里可以添加代码来更新UI显示临时距离，例如：
          // statusBar.value = `当前段距离: ${tempDistance.toFixed(2)} 米`;
        }
      }
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

  // 注册右键点击事件处理函数，用于完成绘制
  handler.setInputAction(() => {
    // 在完成时添加总距离标签
    if (positions.value.length > 1) {
      // 在最后一个点位置添加总距离标签
      const finalPosition = positions.value[positions.value.length - 1]
      cesiumStore.viewerCesium.entities.add({
        position: finalPosition,
        label: {
          ...STYLES.TOTAL_LABEL, // 应用总距离标签样式
          text: `总距离: ${accumulatedDistance.toFixed(2)} 米`, // 格式化总距离文本
        },
      })

      // 确保最终的线段显示是固定的（不再跟随鼠标）
      if (polylineEntity) {
        polylineEntity.polyline.positions = positions.value
      }
    }

    // 销毁事件句柄，防止内存泄漏
    handler.destroy()

    // 返回清理函数，用于在需要时清除所有实体
    return {
      cleanup: () => {
        // 清除所有创建的实体
        pointEntities.forEach((entity) => cesiumStore.viewerCesium.entities.remove(entity))
        segmentLabelEntities.forEach((entity) => cesiumStore.viewerCesium.entities.remove(entity))
        if (polylineEntity) cesiumStore.viewerCesium.entities.remove(polylineEntity)
      },
    }
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
// /**
//  * 计算两点之间的距离
//  */
// const calculateSegmentDistance = (point1, point2) => {
//   // 将笛卡尔坐标转换为地理坐标(经度、纬度、高度)
//   const point1Cartographic = Cesium.Cartographic.fromCartesian(point1)
//   const point2Cartographic = Cesium.Cartographic.fromCartesian(point2)

//   // 创建椭球测地线对象
//   const geodesic = new Cesium.EllipsoidGeodesic() //椭球体上初始化测地线。

//   // 设置测地线的起点和终点
//   geodesic.setEndPoints(point1Cartographic, point2Cartographic) //设置测地线的起点和终点

//   // 获取地表距离  获取起点和终点之间的曲面距离
//   const surfaceDistance = geodesic.surfaceDistance

//   // 计算高度差
//   const heightDifference = point2Cartographic.height - point1Cartographic.height

//   // 计算三维空间距离    一个直角三角形
//   //   P2 (点2)
//   //     /|
//   //    / |
//   //   /  | heightDifference (高度差 heightDifference)
//   //  /   |
//   // P1---P2' (点2在地表的投影 surfaceDistance)

//   const spatialDistance = Math.sqrt(Math.pow(surfaceDistance, 2) + Math.pow(heightDifference, 2))

//   // 返回格式化为两位小数的距离
//   return spatialDistance.toFixed(2) //数字格式化为两位小数的字符串
// }

const pickObj = () => {
  // 创建一个事件处理器
  const handler = new Cesium.ScreenSpaceEventHandler(cesiumStore.viewerCesium.canvas)

  // 监听左键点击事件
  handler.setInputAction(function (click) {
    // 从点击事件获取windowPosition
    const windowPosition = click.position
    // scene.pick ( (windowPosition type Cartesian2) 要执行选取的窗口坐标。, width拾取矩形的宽度。 ,height拾取矩形的高度 )
    // 该属性包含场景中特定窗口坐标处的第一个（顶部）基元，如果该位置没有任何内容，则返回 undefined。
    // 根据基元的类型，可能会设置其他属性，并可用于进一步标识拾取的对象。
    // 尝试拾取对象  返回包含选取的基元的对象。
    const pickedObject = cesiumStore.viewerCesium.scene.pick(windowPosition)

    //defined  如果对象已定义，则返回 true，否则返回 false。
    if (Cesium.defined(pickedObject)) {
      // 拾取到了对象
      console.log('拾取到对象:', pickedObject)
    } else {
      // 没有拾取到对象，尝试获取地球表面的点
      const ray = cesiumStore.viewerCesium.camera.getPickRay(windowPosition)
      const cartesian = cesiumStore.viewerCesium.scene.globe.pick(
        ray,
        cesiumStore.viewerCesium.scene,
      )

      if (Cesium.defined(cartesian)) {
        // 获取到了地球表面的点
        const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
        const longitude = Cesium.Math.toDegrees(cartographic.longitude)
        const latitude = Cesium.Math.toDegrees(cartographic.latitude)
        const height = cartographic.height

        console.log(`点击位置: 经度=${longitude}, 纬度=${latitude}, 高度=${height}米`)
      }
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
</script>

<style lang="scss" scoped></style>
